package cn.lei.netty.herostory;

import cn.lei.netty.herostory.msg.GameMsgProtocol;
import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * 消息识别器
 *
 * @author lil
 */
public class GameMsgRecognizer {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(GameMsgRecognizer.class);

    /**
     * 消息编码 -> 消息对象字典
     */
    private static final Map<Integer, GeneratedMessageV3> MSG_CODE_AND_MSG_OBJ_MAP = new HashMap<>();

    /**
     * 消息类 -> 消息编号字典
     */
    private static final Map<Class<?>, Integer> CLAZZ_AND_MSG_CODE_MAP = new HashMap<>();

    /**
     * 私有化默认构造器
     */
    private GameMsgRecognizer() {

    }

    /**
     * 消息识别器字典初始化
     */
    public static void init() {
        LOGGER.info("====完成消息类和消息编号映射====");

        //获取内部类
        Class<?>[] innerClazzArray = GameMsgProtocol.class.getDeclaredClasses();

        for (Class<?> innerClazz : innerClazzArray) {

            if (innerClazz == null || !GeneratedMessageV3.class.isAssignableFrom(innerClazz)) {
                //如果不是消息表
                continue;
            }
            //获取类名称并小写
            String clazzName = innerClazz.getSimpleName();
            clazzName = clazzName.toLowerCase();

            for (GameMsgProtocol.MsgCode msgCode : GameMsgProtocol.MsgCode.values()) {
                if (msgCode == null) {
                    return;
                }

                //获取消息编码并小写和去掉 "_"
                String strMsgCode = msgCode.name();
                strMsgCode = strMsgCode.replaceAll("_", "").toLowerCase();

                if (!strMsgCode.startsWith(clazzName)) {
                    continue;
                }

                try {
                    //调用静态方法getDefaultInstance,获取实例
                    Object returnObj = innerClazz.getDeclaredMethod("getDefaultInstance").invoke(innerClazz);

                    LOGGER.info("{} <==> {}", innerClazz.getName(), msgCode.getNumber());

                    //[消息编码 -> 消息对象] 字典
                    MSG_CODE_AND_MSG_OBJ_MAP.put(msgCode.getNumber(), (GeneratedMessageV3) returnObj);

                    //[消息类 -> 消息编号] 字典
                    CLAZZ_AND_MSG_CODE_MAP.put(innerClazz, msgCode.getNumber());
                } catch (Exception ex) {
                    LOGGER.info(ex.getMessage(), ex);
                }

            }
        }
    }

    /**
     * 根据消息编号获取消息构造器
     *
     * @param msgCode
     * @return
     */
    public static Message.Builder getBuilderByMsgCode(int msgCode) {
        if (msgCode < 0) {
            return null;
        }
        GeneratedMessageV3 defaultMsg = MSG_CODE_AND_MSG_OBJ_MAP.get(msgCode);

        if (defaultMsg == null) {
            return null;
        } else {
            return defaultMsg.newBuilderForType();
        }
    }

    /**
     * 根据消息类获取消息编号
     *
     * @param msgClazz
     * @return
     */
    public static int getMsgByClazz(Class<?> msgClazz) {
        if (msgClazz == null) {
            return -1;
        }
        Integer msgCode = CLAZZ_AND_MSG_CODE_MAP.get(msgClazz);
        if (msgCode == null) {
            return -1;
        } else {
            return msgCode;
        }
    }
}
